home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
fish
/
726-750
/
727
/
2view
/
source
/
2view.c
next >
Wrap
C/C++ Source or Header
|
1995-03-18
|
21KB
|
728 lines
/***********************************************************************\
* 2View V1.52 *
* A simple, fast ILBM viewer, for use under AmigaOS V2.x. *
* Written and ©1991-1992 by Dave Schreiber. All Rights Reserved. *
* *
* Usage: *
* 2View FILE/A/M,FROM/K,SECS=SECONDS/K/N,TICKS/K/N,LOOP/S,PRINT *
* *
* Where the following arguments are defined as follows: *
* FILE - The name of one (or more) IFF ILBM files *
* FROM - A file containing a list of filenames. Used instead of FILE *
* SECS - Number of seconds to display a file *
* TICKS - Number of ticks (1/60ths of a second) *
* LOOP - When finished showing the last pictures, start over *
* PRINT - Print each picture as it is shown *
* *
* To compile (with SAS/C V5.10a): *
* lc -v 2View ARexx *
* lc -v -b0 Misc *
* asm 2ViewAsm.a *
* blink with 2View.lnk *
* *
* Version history: *
* 1.52 - Fixed a bug that would cause 2View to crash if it was *
* given an ILBM of more than 8 bitplanes. *
* Released on August 30, 1992 *
* 1.51 - Added support for 2.0-style wildcards. *
* Released on August 17, 1992 *
* *
* 1.50 - Rewrote the subroutine that reads the ILBM from disk in *
* assembly language, for speed. Added support for SHAM and *
* Macro Paint images, and for color cycling (both *
* traditional (CRNG, i.e. continutout cycle ranges) and *
* DPaint-IV style cycling (DRNG, i.e. non-continuous cycle *
* ranges). A 'tick' (as used with the "TICK" keyword, above)*
* has been redefined as 1/60th of a second. Finally, the *
* source code in 2View.c has been split into two files *
* (2View.c and Misc.c). *
* Released 3/24/92 *
* *
* 1.11 - Improved error reporting (with this version, if the user *
* run 2View from Workbench and there's an error, a requester *
* is put up. Previously, the user was not notified at all *
* of the error). *
* Released 9/11/91 *
* *
* 1.10 - Added support for Workbench, ARexx, scrollable bitmaps, *
* and printing. Also, the user can now use CTRL-C to advance*
* to the next frame, and CTRL-D to abort a playlist. *
* Released 9/3/91 *
* *
* 1.00 - Original version. Released 7/24/91 *
* *
\************************************************************************/
unsigned long availBytes,curPos,bufSize;
/*Include files*/
#include <exec/types.h>
#include <libraries/iffparse.h>
#include <dos/dos.h>
#include <dos/dosasl.h>
#include <intuition/intuition.h>
#include <exec/memory.h>
#include <workbench/startup.h>
#include <graphics/gfxbase.h>
/*Prototypes*/
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/iffparse_protos.h>
/*Pragmas*/
#include <pragmas/exec_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/iffparse_pragmas.h>
#include <pragmas/dos_pragmas.h>
/*Other include files*/
#include "iff.h"
#include "2View.h"
#include "arexx.h"
/*Libraries we'll need*/
struct Library *IFFParseBase=NULL;
struct Library *IntuitionBase=NULL;
struct GfxBase *GfxBase=NULL;
/*Provided by the compiler*/
extern struct Library *SysBase;
extern struct Library *DOSBase;
/*Generic screen and window definitions. They will be used to define*/
/*the screen and window that the various pictures will be shown on*/
struct NewScreen newScreen=
{
0,0,0,0,0,1,0,NULL,CUSTOMSCREEN|SCREENBEHIND|AUTOSCROLL,NULL,NULL,NULL,
NULL
};
struct NewWindow newWindow =
{
0,0,0,0,0,1,MENUDOWN|SELECTDOWN|ACTIVEWINDOW|VANILLAKEY,
RMBTRAP|BORDERLESS|NOCAREREFRESH,NULL,NULL,NULL,NULL,NULL,
0,0,640,400,CUSTOMSCREEN
};
struct Screen *screen=NULL;
struct Window *window=NULL;
/*------------------------------------------------------------------------*/
UWORD *storage;
int counter;
/*A true here indicates the current ILBM file is compressed*/
BYTE Compression;
/*An error message that used in various places*/
char *errorMsg="An error occured while reading ";
/*The version string. Do a 'version 2View' to display it*/
char *version="$VER: QView V1.52 (30.8.92)";
/*Just so that the © message is part of the actual program*/
char *copyRightMsg="Copyright 1991-1992 by Dave Schreiber. All Rights Reserved.";
BYTE ExitFlag=FALSE; /*'Exit now' flag*/
UWORD ticks=0; /*Delay requested by user.*/
/*The previous screen and window*/
struct Window *prevWindow=NULL;
struct Screen *prevScreen=NULL;
/*Data for a blank pointer*/
UWORD chip fakePointerData[]={0,0,0,0,0};
struct IFFHandle *iff=NULL; /*IFF handle*/
BPTR pL=NULL; /*Playlist file pointer*/
BOOL masking,print,toFront,printPics;
extern struct WBStartup *WBenchMsg;
char *playListFilename=NULL;
/*Variables that have to be global so that ARexx.c can access them*/
ButtonTypes rexxAbort=none;
extern void dispRexxPort(void);
extern void dnRexxPort();
long arexxSigBit;
UWORD ticksRemaining=0;
BOOL loop=FALSE;
BYTE specialModes;
char *picFilename;
char trashBuf[512]; /* A place to dump mask information */
char *buf=trashBuf;
void _main();
struct TagItem TagList[]=
{
/* This defines what part of the displayed picture is shown. It's */
/* necessary to have a line like this in here in order to get */
/* 2.0 autoscrolling to work. */
{SA_Overscan,OSCAN_VIDEO},
{TAG_DONE,NULL}
};
char *about1="2View";
char *about2="Please";
extern struct EasyStruct erError1Line;
BOOL cycle=FALSE;
UBYTE numColors;
UWORD destMap[32];
UBYTE numCycleColors;
UBYTE rate;
/* The assembly-language reader routine */
extern int ReadIntoBitMapAsm(PLANEPTR,APTR,struct IFFHandle *,
ULONG,ULONG,UWORD,UBYTE,UBYTE,UBYTE);
char **filenames;
UWORD numFilenames=0,numSlots;
struct AnchorPath *anchorPath=NULL;
/*------------------------------------------------------------------------*/
void _main()
{
UWORD c;
LONG args[7];
char **filenames;
char curFilename[256];
BOOL playList; /*True if a playlist is being used, false otherwise*/
BYTE status=0;
/*Allocate the pattern matching anchor*/
anchorPath=(struct AnchorPath *)
AllocMem(sizeof(struct AnchorPath),MEMF_CLEAR);
if(anchorPath==NULL)
exit(99);
/*Initialize the argument buffers to NULL*/
for(c=0;c<7;c++)
args[c]=NULL;
openResources(args,&playList,&filenames);
/*Run until we run out of filenames, or the user aborts*/
while(!ExitFlag)
{
picFilename=curFilename; /*Get a pointer to the filename buffer*/
/*Check to see if we're running from Workbench. If so, and the*/
/*user provided names of pictures to display (by clicking on their*/
/*icons), display those pictures*/
if(WBenchMsg!=NULL && WBenchMsg->sm_NumArgs>1)
{
CurrentDir(WBenchMsg->sm_ArgList[1].wa_Lock);
picFilename=WBenchMsg->sm_ArgList[1].wa_Name;
}
else if(playList) /*If a playlist is being used*/
{
pL=Open(playListFilename,MODE_OLDFILE); /*Open the playlist*/
if(pL==NULL) /*If we couldn't open the playlist, abort*/
{
printError("Can't open playlist","");
cleanup();
exit(199);
}
do /*Loop until we run out of playlist, or get a valid name*/
{
if(FGets(pL,picFilename,140)==NULL) /*If end-of-file*/
picFilename=NULL; /*Set as NULL as a flag*/
}
while(picFilename!=NULL && picFilename[0]==0x0A);
if(picFilename!=NULL) /*If not NULL, it's a valid filename*/
picFilename[strlen(picFilename)-1]=NULL; /*Remove the linefeed*/
}
else /*Otherwise, if a playlist isn't being used, get the current*/
{ /*filename*/
GetFilename(picFilename,filenames,anchorPath,&status);
}
/*Loop while the user hasn't requested an abort, and while*/
/*there are still files to display*/
for(c=0;!ExitFlag && picFilename[0]!=NULL;c++)
{
if((iff->iff_Stream=Open(picFilename,MODE_OLDFILE))==NULL)
{ /*If the ILBM file can't be opened...*/
/*Print an error...*/
printError("Can't open: ", picFilename);
cleanup();
exit(200);
}
InitIFFasDOS(iff); /*The IFF file will be read from disk*/
OpenIFF(iff,IFFF_READ); /*Make iffparse.library aware of the*/
/*ILBM file*/
/*Read in the file and display*/
ReadAndDisplay(picFilename,iff);
CloseIFF(iff); /*Release iffparse's hold on the file*/
Close(iff->iff_Stream); /*Close the file*/
/*Get the next filename, either from Workbench,*/
if(WBenchMsg!=NULL)
{
if(WBenchMsg->sm_NumArgs > c+2)
{
CurrentDir(WBenchMsg->sm_ArgList[c+2].wa_Lock);
picFilename=WBenchMsg->sm_ArgList[c+2].wa_Name;
}
else
picFilename=NULL;
}
else if(playList) /*The playlist*/
{
do
{
if(FGets(pL,picFilename,140)==NULL)
picFilename=NULL;
}
while(picFilename!=NULL && picFilename[0]==0x0A);
if(picFilename!=NULL)
picFilename[strlen(picFilename)-1]=NULL;
}
else /*or the command line*/
GetFilename(picFilename,filenames,anchorPath,&status);
}
/*We're finished with this run of pictures*/
if(playList) /*Close playlist, if open*/
Close(pL);
pL=NULL;
if(!loop && !printPics) /*If the loop flag wasn't given, exit*/
ExitFlag=TRUE;
}
/*Time to exit, so close stuff*/
cleanup();
exit(0); /*And exit*/
}
LONG ilbmprops[] = { ID_ILBM,ID_CMAP,ID_ILBM,ID_BMHD,ID_ILBM,ID_CAMG,
ID_ILBM,ID_CRNG,ID_ILBM,ID_DRNG,ID_ILBM,ID_SHAM,
ID_ILBM,ID_CTBL };
/*Read in an ILBM file and display it*/
void ReadAndDisplay(char *filename,struct IFFHandle *iff)
{
int error;
UBYTE *bodyBuffer; /*Pointer to buffer holding 'BODY' chunk info*/
ULONG ViewModes; /*Holds the viewmodes flags*/
UWORD c;
ButtonTypes button;
UBYTE cycleTable[32];
UBYTE countDown;
/*Structures required for IFF parsing*/
struct StoredProperty *bmhd,*cmap,*camg,*crng,*drng,*sham,*ctbl;
struct ContextNode *bodyContext;
/*IntuiMessage...*/
struct IntuiMessage *mesg;
/*Indentify chunks that should be stored during parse*/
/*(in this case, CMAP, BMHD, CRNG, DRNG, CAMG, and SHAM)*/
error=PropChunks(iff,ilbmprops,7);
/*If there was an error, print a message and return*/
if(error!=0)
{
printError(errorMsg,filename);
ExitFlag=TRUE;
return;
}
/*Tell iffparse to stop at a 'BODY' chunk*/
error=StopChunk(iff,ID_ILBM,ID_BODY);
/*Error handling yet again*/
if(error!=0 && error!=-1)
{
printError(errorMsg,filename);
ExitFlag=TRUE;
return;
}
/*Do the actual parsing*/
error=ParseIFF(iff,IFFPARSE_SCAN);
/*Check for errors yet again*/
if(error!=0 && error !=-1)
{
printError(errorMsg,filename);
ExitFlag=TRUE;
return;
}
/*Get the chunks that were found in the file*/
bmhd = FindProp(iff,ID_ILBM,ID_BMHD); /*Bitmap information*/
cmap = FindProp(iff,ID_ILBM,ID_CMAP); /*Color map*/
camg = FindProp(iff,ID_ILBM,ID_CAMG); /*Amiga viewmode information*/
crng = FindProp(iff,ID_ILBM,ID_CRNG); /*Color-cycling ranges*/
drng = FindProp(iff,ID_ILBM,ID_DRNG); /*New (DPaint IV) color-cycling*/
sham = FindProp(iff,ID_ILBM,ID_SHAM); /*SHAM color tables*/
ctbl = FindProp(iff,ID_ILBM,ID_CTBL); /*Macro Paint color table info*/
/*Get the descriptor for the BODY chunk*/
bodyContext=CurrentChunk(iff);
/*If there wasn't a BMHD, CMAP, or BODY chunk, abort*/
if(!bmhd | !cmap | !bodyContext)
{
printError(filename," is corrupted or is not in Amiga ILBM format");
ExitFlag=TRUE;
return;
}
/*Prepare to determine screen modes*/
newScreen.ViewModes=NULL;
/*If there was a CAMG chunk, use it to get the viewmodes*/
if(camg!=NULL)
{
ViewModes=( ((CAMG *)(camg->sp_Data))->viewmodes );
if(ViewModes & HAM)
newScreen.ViewModes|=HAM;
if(ViewModes & EXTRA_HALFBRITE)
newScreen.ViewModes|=EXTRA_HALFBRITE;
if(ViewModes & LACE)
newScreen.ViewModes|=LACE;
if(ViewModes & HIRES)
newScreen.ViewModes|=HIRES;
}
if(crng==NULL)
if(drng==NULL) /*No color cycling*/
numCycleColors=0;
else /* DPaint-IV--style color cycling*/
numCycleColors=interpretDRNG(cycleTable,(DRNG *)(drng->sp_Data),&rate);
else /*DPaint I-III--style color cycling*/
numCycleColors=interpretCRNG( cycleTable,(CRNG *)(crng->sp_Data),&rate);
if(numCycleColors != 0)
cycle=TRUE; /*Start cycling if there are colors to cycle*/
else
cycle=FALSE;
/*Interpret the BMHD chunk*/
getBMHD((struct BitMapHeader *)bmhd->sp_Data);
if(newScreen.Depth>8)
{
printError(filename," has more than 8 bitplanes");
ExitFlag=TRUE;
return;
}
/*Don't open an interlace screen if the image is in SHAM mode*/
/*(the Amiga OS doesn't properly handle user copper lists on */
/*interlaced screens for some reason)*/
if(sham!=NULL)
newScreen.ViewModes&=~LACE;
/*Open a screen, defined by the BMHD and CAMG chunks*/
screen=OpenScreenTagList(&newScreen,TagList);
/*If the screen couldn't be opened, abort*/
if(screen==NULL)
{
printError("Cannot open screen!","");
ExitFlag=TRUE;
return;
}
/*This more properly centers the screen, for some reason */
MoveScreen(screen,1,1);
MoveScreen(screen,-1,-1);
/*Set the window dimensions from the screen dimensions*/
newWindow.Screen=screen;
newWindow.Width=newScreen.Width;
newWindow.Height=newScreen.Height;
/*Open the window*/
window=OpenWindow(&newWindow);
/*Abort if the window couldn't be opened*/
if(window==NULL)
{
printError("Cannot open window!","");
ExitFlag=TRUE;
return;
}
/*Allocate enough memory to hold the BODY data*/
/*We want to find out what the biggest block of memory is. If*/
/*we have enough memory to hold the entire body chunk, we'll load*/
/*the whole thing into memory and decompress from there. If not,*/
/*we'll load as much as we can and refill the buffer when it*/
/*empties*/
/*We do a Forbid() to keep anyone from allocating memory between*/
/*the AvailMem() and AllocMem() calls. This way, we're guaranteed*/
/*that a memory block of the size given by Availmem() can be */
/*allocated. For this reason, we don't need to check the result*/
/*of the AllocMem(); we're guaranteed that it worked*/
Forbid();
bufSize=AvailMem(MEMF_LARGEST);
bufSize=MIN(bufSize,bodyContext->cn_Size+1);
if(bufSize==0) /*It'll never happen, but just in case...*/
{
Permit();
ExitFlag=TRUE;
return;
}
bodyBuffer=AllocMem(bufSize,0L);
Permit();
availBytes = bufSize;
curPos = bufSize;
/*Blank out the pointer*/
SetPointer(window,fakePointerData,1,16,0,0);
/*Set the screen colors to those provided in the CMAP chunk*/
setScreenColors(screen,cmap->sp_Data,newScreen.Depth,destMap,&numColors);
/*Uncompress an ILBM and copy it into the bitmap*/
if(ReadIntoBitmapAsm(&(screen->BitMap.Planes),bodyBuffer,iff,bufSize,
(ULONG)screen->BitMap.BytesPerRow,
screen->BitMap.Rows,
screen->BitMap.Depth,(Compression==1) ? 1 : 0,
(masking) ? 1 : 0))
{
printError(errorMsg,"");
cleanup();
exit(2000);
}
/*Activate the window, and flush any IDCMP message*/
ActivateWindow(window);
while((mesg=(struct IntuiMessage *)GetMsg(window->UserPort))!=NULL)
ReplyMsg((struct Message *)mesg);
/*If this is a SHAM image, setup the copper list appropriately*/
if(sham!=NULL)
{
specialModes=SHAM;
setupSHAM(screen,(UWORD *)(sham->sp_Data));
}
else
/*If this is a MacroPaint image, setup the copper list*/
if(ctbl!=NULL)
{
specialModes=MACROPAINT;
setupDynHires(screen,(UWORD *)(ctbl->sp_Data));
}
else
/* Otherwise, this is a normal ILBM*/
specialModes=NORMAL;
/*Bring the screen to the front*/
ScreenToFront(screen);
/*If the user used the 'print' flag on the command line, print*/
/*the picture (but not if this is a SHAM or MacroPaint image)*/
if(printPics && specialModes == NORMAL)
dumpRastPort(&(screen->RastPort),&(screen->ViewPort));
print=TRUE;
/*Close the previous window and screen*/
if(prevWindow!=NULL)
CloseWindow(prevWindow);
if(prevScreen!=NULL)
CloseScreen(prevScreen);
/*Free the buffer that holds the BODY chunk information*/
FreeMem(bodyBuffer,bufSize);
/*Store the current window & screen structures, so they can be*/
/*closed later*/
prevWindow=window;
prevScreen=screen;
screen=NULL;
window=NULL;
rexxAbort=none;
countDown=rate;
if(ticks==0) /*If ticks==0, this means that no delay was specified*/
{ /*by the user. So just wait for him to click a button*/
int prevTopEdge=prevScreen->TopEdge;
while((button=checkButton())==none && rexxAbort==none)
{
/*Wait for 1/60th of a second*/
WaitTOF();
/*Refresh the SHAM copper list if required*/
if(prevTopEdge!=prevScreen->TopEdge && sham!=NULL)
{
prevTopEdge=prevScreen->TopEdge;
setupSHAM(prevScreen,(UWORD *)(sham->sp_Data));
}
/*Refresh the MacroPaint copper list if required*?
if(prevTopEdge!=prevScreen->TopEdge && ctbl!=NULL)
{
prevTopEdge=prevScreen->TopEdge;
setupDynHires(prevScreen,(UWORD *)(ctbl->sp_Data));
}
/*If its time to cycle the colors, then cycle them*/
if(cycle && numCycleColors!=0 && --countDown==0)
{
cycleColors(cycleTable,destMap,numCycleColors,numColors);
countDown=rate;
}
dispRexxPort();
}
/*Check to see if the user wants to abort*/
if(button==menu || rexxAbort==menu)
ExitFlag=TRUE;
}
else /*Otherwise, wait for the specified amount of time*/
{
for(c=0;c<ticks;c++)
{
/*Wait 1/60th of a second*/
WaitTOF();
/*Cycle colors if necessary*/
if(cycle && numCycleColors!=0 && --countDown==0)
{
cycleColors(cycleTable,destMap,numCycleColors,numColors);
countDown=rate;
}
dispRexxPort(); /*Check ARexx port*/
button=checkButton(); /*After each 25 ticks, check to see if*/
if(button==menu || rexxAbort==menu) /*the user wants to abort*/
{
ExitFlag=TRUE;
return;
}
if(button==select || rexxAbort==select) /*Or advance prematurely*/
return;
}
}
}
void GetFilename(char *picFilename,char **filenames,struct AnchorPath *anchor,
BYTE *status)
{
int err=1;
picFilename[0]=NULL;
if(*status==0)
{
while(err!=0 && filenames[*status]!=NULL)
{
err=MatchFirst(filenames[(*status)++],anchor);
if(err!=0 && !containsWildcards(filenames[(*status)-1]))
{
printError("Cannot open ",filenames[(*status)-1]);
cleanup();
exit(1000);
}
}
if(err!=0)
return;
else
{
NameFromLock(anchor->ap_Base->an_Lock,picFilename,256);
if(picFilename[strlen(picFilename)-1]!=':')
strcat(picFilename,"/");
strcat(picFilename,anchor->ap_Info.fib_FileName);
*status++;
return;
}
}
err=MatchNext(anchor);
if(err!=0)
{
MatchEnd(anchor);
while(err!=0 && filenames[*status]!=NULL)
{
if(err!=0 && !containsWildcards(filenames[(*status)-1]))
{
printError("Cannot open ",filenames[(*status)-1]);
cleanup();
exit(1010);
}
err=MatchFirst(filenames[(*status)++],anchor);
}
if(err!=0)
return;
else
{
NameFromLock(anchor->ap_Base->an_Lock,picFilename,256);
if(picFilename[strlen(picFilename)-1]!=':')
strcat(picFilename,"/");
strcat(picFilename,anchor->ap_Info.fib_FileName);
return;
}
}
else
{
NameFromLock(anchor->ap_Base->an_Lock,picFilename,256);
if(picFilename[strlen(picFilename)-1]!=':')
strcat(picFilename,"/");
strcat(picFilename,anchor->ap_Info.fib_FileName);
return;
}
}
char tokens[]={'?','#','(','~','[','%','*'};
#define NUMTOKENS (7)
/*Checks to see if a filename contains wildcard tokens (i.e. whether the*/
/*given string is a filename or filepattern)*/
BOOL containsWildcards(char *filename)
{
int c,token;
for(token=0;token<NUMTOKENS;token++)
for(c=0;filename[c]!=NULL;c++)
if(filename[c]==tokens[token])
return(TRUE);
return(FALSE);
}
/*End of 2View.c*/